/* 
 * File:   Config.cpp
 * Author: ja1e09
 * 
 * Created on July 29, 2011, 12:13 PM
 */

#include "Config.h"

Config* Config::pInstance = 0;

Config::Config(void)
{
}

Config* Config::GetInstance(void)
{
    if (pInstance == 0)
        pInstance = new Config;

    return pInstance;
}

void Config::Destroy(void)
{
    if (pInstance != 0)
    {
        SAFE_DELETE(pInstance);
    }
}

const bool Config::AddIntToMap(const char* pName, const int iData)
{
    mConfig[pName] = iData;

    std::ostringstream ssLogMsg;
    ssLogMsg << "Config::AddItemToMap::Added/Updated: [" << pName << "," << "INT" << "," << boost::any_cast<int>(mConfig[pName]) << "]";
    Console::GetInstance()->Add(ssLogMsg.str());

    return true;
}

const bool Config::AddUIntToMap(const char* pName, const unsigned int uData)
{
    mConfig[pName] = uData;

    std::ostringstream ssLogMsg;
    ssLogMsg << "Config::AddItemToMap::Added/Updated: [" << pName << "," << "UINT" << "," << boost::any_cast<unsigned int>(mConfig[pName]) << "]";
    Console::GetInstance()->Add(ssLogMsg.str());

    return true;
}

const bool Config::AddFPToMap(const char* pName, const float fData)
{
    mConfig[pName] = fData;

    std::ostringstream ssLogMsg;
    ssLogMsg << "Config::AddItemToMap::Added/Updated: [" << pName << "," << "FP" << "," << boost::any_cast<float>(mConfig[pName]) << "]";
    Console::GetInstance()->Add(ssLogMsg.str());

    return true;
}

const bool Config::AddDFPToMap(const char* pName, const double dData)
{
    mConfig[pName] = dData;

    std::ostringstream ssLogMsg;
    ssLogMsg << "Config::AddItemToMap::Added/Updated: [" << pName << "," << "DFP" << "," << boost::any_cast<double>(mConfig[pName]) << "]";
    Console::GetInstance()->Add(ssLogMsg.str());

    return true;
}

const bool Config::AddBoolToMap(const char* pName, const bool bData)
{
    mConfig[pName] = bData;

    std::ostringstream ssLogMsg;
    ssLogMsg << "Config::AddItemToMap::Added/Updated: [" << pName << "," << "BOOL" << "," << boost::any_cast<bool>(mConfig[pName]) << "]";
    Console::GetInstance()->Add(ssLogMsg.str());

    return true;
}

const bool Config::AddStrToMap(const char* pName, const std::string sData)
{
    mConfig[pName] = sData;

    std::ostringstream ssLogMsg;
    ssLogMsg << "Config::AddItemToMap::Added/Updated: [" << pName << "," << "STR" << "," << boost::any_cast<std::string > (mConfig[pName]) << "]";
    Console::GetInstance()->Add(ssLogMsg.str());

    return true;
}

const int Config::GetTypeFromStr(const char* pType)
{
    if (!pType)
    {
        // Error NULL pointer
        return -1;
    }

    // TYPE_INT, TYPE_UINT, TYPE_FP, TYPE_DFP, TYPE_BOOL, TYPE_STR, TYPE_LONG

    if (strcmp(pType, "INT") == 0)
        return TYPE_INT;

    if (strcmp(pType, "UINT") == 0)
        return TYPE_UINT;

    if (strcmp(pType, "FP") == 0)
        return TYPE_FP;

    if (strcmp(pType, "DFP") == 0)
        return TYPE_DFP;

    if (strcmp(pType, "BOOL") == 0)
        return TYPE_BOOL;

    if (strcmp(pType, "STR") == 0)
        return TYPE_STR;

    if (strcmp(pType, "LONG") == 0)
        return TYPE_LONG;

    return -1;
}

const bool Config::AddItemToMap(const char* pName, const char* pType, const char* pData)
{
    std::ostringstream ssLogMsg;

    int iType;
    iType = GetTypeFromStr(pType);
    if (iType < 0)
    {
        ssLogMsg << "Config::AddItemToMap::ERROR::Trying to add an invalid data type." << std::endl;
        Console::GetInstance()->Add(ssLogMsg.str());
        return false;
    }

    switch (iType)
    {
        // Integer
    case 0:
    {
        mConfig[pName] = atoi(pData);
        ssLogMsg << "Config::AddItemToMap::Added from XML: [" << pName << "," << pType << "," << boost::any_cast<int>(mConfig[pName]) << "]";
        Console::GetInstance()->Add(ssLogMsg.str());
        break;
    }
        // Unsigned Integer
    case 1:
    {
        mConfig[pName] = (unsigned int) atoi(pData);
        ssLogMsg << "Config::AddItemToMap::Added from XML: [" << pName << "," << pType << "," << boost::any_cast<unsigned int>(mConfig[pName]) << "]";
        Console::GetInstance()->Add(ssLogMsg.str());
        break;
    }
        // Float
    case 2:
    {
        mConfig[pName] = (float) atof(pData);
        ssLogMsg << "Config::AddItemToMap::Added from XML: [" << pName << "," << pType << "," << boost::any_cast<float>(mConfig[pName]) << "]";
        Console::GetInstance()->Add(ssLogMsg.str());
        break;
    }
        // Double
    case 3:
    {
        mConfig[pName] = atof(pData);
        ssLogMsg << "Config::AddItemToMap::Added from XML: [" << pName << "," << pType << "," << boost::any_cast<double>(mConfig[pName]) << "]";
        Console::GetInstance()->Add(ssLogMsg.str());
        break;
    }
        // BOOL
    case 4:
    {
        mConfig[pName] = (bool)atoi(pData);
        ssLogMsg << "Config::AddItemToMap::Added from XML: [" << pName << "," << pType << "," << boost::any_cast<bool>(mConfig[pName]) << "]";
        Console::GetInstance()->Add(ssLogMsg.str());
        break;
    }
        //String
    case 5:
    {
        std::string sData(pData);
        mConfig[pName] = sData;
        ssLogMsg << "Config::AddItemToMap::Added from XML: [" << pName << "," << pType << "," << boost::any_cast<std::string > (mConfig[pName]) << "]";
        Console::GetInstance()->Add(ssLogMsg.str());
        break;
    }
    };

    return true;
}

const std::string Config::GetStr(const char* pName)
{
    return boost::any_cast<std::string > (mConfig[pName]);
}

const float Config::GetFP(const char* pName)
{
    return boost::any_cast<float>(mConfig[pName]);
}

const double Config::GetDFP(const char* pName)
{
    return boost::any_cast<double>(mConfig[pName]);
}

const bool Config::GetBool(const char* pName)
{
    return boost::any_cast<bool>(mConfig[pName]);
}

const int Config::GetInt(const char* pName)
{
    return boost::any_cast<int>(mConfig[pName]);
}

const unsigned int Config::GetUInt(const char* pName)
{
    return boost::any_cast<unsigned int>(mConfig[pName]);
}

const bool Config::Init()
{
    // Clear XML
    XML_Config.Clear();

    // MPI Load XML file into memory

    Console::GetInstance()->Add("Config::Init::Loading config XML file ... ");
    
    // Parse XML file with TinyXML
    bool bRes = XML_Config.LoadFile(CONFIG_FILE);
    //bool bRes = XML_Config.Parse();
    if (!bRes)
    {
        std::ostringstream ssLogMsg;
        ssLogMsg << "Config::Init::ERROR::Could not load config file. Error: " << XML_Config.ErrorDesc() << std::endl;
        Console::GetInstance()->Add(ssLogMsg.str());
        return false;
    }

    // Dump XML attributes to boost::any map type container
    TiXmlNode* XML_Root = XML_Config.RootElement();

    for (TiXmlElement* XML_Item = XML_Root->FirstChildElement(); XML_Item; XML_Item = XML_Item->NextSiblingElement())
        if (!(AddItemToMap(XML_Item->Attribute("Name"), XML_Item->Attribute("Type"), XML_Item->Attribute("Value"))))
            return false;

    // Clear XML
    XML_Config.Clear();

    Console::GetInstance()->Add("Config::Init::File Loaded.");

    return true;
}